//存在一个由 n 个节点组成的无向连通图，图中的节点按从 0 到 n - 1 编号。 
//
// 给你一个数组 graph 表示这个图。其中，graph[i] 是一个列表，由所有与节点 i 直接相连的节点组成。 
//
// 返回能够访问所有节点的最短路径的长度。你可以在任一节点开始和停止，也可以多次重访节点，并且可以重用边。 
//
// 
//
// 
// 
//
// 示例 1： 
//
// 
//输入：graph = [[1,2,3],[0],[0],[0]]
//输出：4
//解释：一种可能的路径为 [1,0,2,0,3] 
//
// 示例 2： 
//
// 
//
// 
//输入：graph = [[1],[0,2,4],[1,3,4],[2],[1,2]]
//输出：4
//解释：一种可能的路径为 [0,1,4,2,3]
// 
//
// 
//
// 提示： 
//
// 
// n == graph.length 
// 1 <= n <= 12 
// 0 <= graph[i].length < n 
// graph[i] 不包含 i 
// 如果 graph[a] 包含 b ，那么 graph[b] 也包含 a 
// 输入的图总是连通图 
// 
// Related Topics位运算 | 广度优先搜索 | 图 | 动态规划 | 状态压缩 
//
// 👍 331, 👎 0 
//
//
//
//

package leetcode.editor.cn;

import java.util.LinkedList;
import java.util.Queue;

class ShortestPathVisitingAllNodes {
    public static void main(String[] args) {
        Solution solution = new ShortestPathVisitingAllNodes().new Solution();
    }

    //leetcode submit region begin(Prohibit modification and deletion)
    // BFS + 状态压缩
    // https://leetcode.cn/problems/shortest-path-visiting-all-nodes/solution/tong-ge-lai-shua-ti-la-bfs-si-lu-zhuan-h-jl3s/
    class Solution {
        public int shortestPathLength(int[][] graph) {
            int n = graph.length;
            int mask = 1 << n;  // 标识有多少位

            // 第一维标识当前节点是否被访问，第二维表示路径的状态
            boolean[][] visited = new boolean[n][mask];
            Queue<int[]> queue = new LinkedList<>();
            for (int i = 0; i < graph.length; i++) {
                // [当前节点,状态]
                queue.offer(new int[]{i, 1 << i});
                // 标记是否被遍历过
                visited[i][1 << i] = true;
            }

            // 记录BFS的层数
            int level = 0;
            while (!queue.isEmpty()) {
                int size = queue.size();
                level++;
                for (int i = 0; i < size; i++) {
                    int[] poll = queue.poll();
                    int cur = poll[0], curStatus = poll[1];
                    for (int next : graph[cur]) {
                        // 按位或，不管第next位是否为1，或之后第next位都是1
                        int nextStatus = curStatus | (1 << next);

                        // 判断是否所有节点都遍历过，也就是状态的每一位都是1
                        if (nextStatus == mask - 1) return level;

                        // 在次状态下没遍历过
                        if (!visited[next][nextStatus]) {
                            visited[next][nextStatus] = true;
                            queue.offer(new int[]{next, nextStatus});
                        }
                    }
                }
            }

            return 0;
        }
    }
//leetcode submit region end(Prohibit modification and deletion)

}
